package webmanage

import (
	"context"
	"errors"
	"fmt"
	"github.com/go-kratos/kratos/v2/log"
	"gorm.io/gorm"
	pb "phm/api/phm/v1/webmanage"
	"phm/auth"
	"phm/models/generator/model"
	"phm/tools"
	mstr "phm/tools/strings"
)

type UserUseCase struct {
	ur  UserRepo
	srr SysRoleRepo
	sor SysOperationRepo
	spr SysPermissionRepo
	sua SysUserAreaRepo
	au  auth.AuthRepo
	log *log.Helper
}

type UserRepo interface {
	CreateUser(ctx context.Context, uModel *model.SysUser, db *gorm.DB) (string, error)
	DeleteUserByIds(ctx context.Context, ids []string, db *gorm.DB) error
	GetUserById(ctx context.Context, id string) (*model.SysUser, error)
	GetUserByUsername(ctx context.Context, username string) (*model.SysUser, error)
	GetUserByIds(ctx context.Context, ids []string) ([]*model.SysUser, error)
	GetUserList(ctx context.Context, query string, pageNum, pageSize int64) ([]*model.SysUser, int64, error)
	// GetDB 得到db以方便事务处理
	GetDB() *gorm.DB
	// TryLogin for redis cache
	TryLogin(ctx context.Context, loginName string) (*model.SysUser, string, error)
}

func NewUserUseCase(sua SysUserAreaRepo, ur UserRepo, srr SysRoleRepo, sor SysOperationRepo, spr SysPermissionRepo, au auth.AuthRepo, logger log.Logger) *UserUseCase {
	return &UserUseCase{
		sua: sua,
		ur:  ur,
		srr: srr,
		sor: sor,
		spr: spr,
		au:  au,
		log: log.NewHelper(logger),
	}
}

func (u *UserUseCase) GetUserList(ctx context.Context, query string, pageNum, pageSize int64) (*pb.QueryUserReply, error) {
	users, total, err := u.ur.GetUserList(ctx, query, pageNum, pageSize)
	if err != nil {
		return nil, err
	}
	var res = []*pb.UserInfo{}
	for _, user := range users {
		var area = []*pb.Area{}
		var info = &pb.UserInfo{}
		areas, _ := u.sua.GetSysAreaByUserId(ctx, user.ID)
		for _, serverArea := range areas {
			area = append(area, &pb.Area{
				AreaId:   *serverArea.ID,
				AreaName: *serverArea.Name,
			})
		}
		info.Area = area
		if user.CertificatesID != nil {
			info.CertificatesId = *user.CertificatesID
		}
		if user.Username != nil {
			info.Username = *user.Username
		}
		if user.JobName != nil {
			info.JobName = *user.JobName
		}
		if user.Mailbox != nil {
			info.Mailbox = *user.Mailbox
		}
		if user.Mobile != nil {
			info.Mobile = *user.Mobile
		}
		if user.RealName != nil {
			info.RealName = *user.RealName
		}
		if user.UserType != nil {
			info.UserType = *user.UserType
		}
		if user.Username != nil {
			info.Username = *user.Username
		}
		res = append(res, info)
	}
	return &pb.QueryUserReply{
		List:     res,
		PageNum:  pageNum,
		PageSize: pageSize,
		RowCount: total,
	}, nil
}

func (u *UserUseCase) CreateUser(ctx context.Context, uModel *model.SysUser) (string, error) {
	tx := u.ur.GetDB().Begin()
	if tx != nil {
		token, err := u.ur.CreateUser(ctx, uModel, tx)
		if err != nil {
			tx.Rollback()
			return "", err
		}
		tx.Commit()
		return token, nil
	}
	return "", mstr.CreateError
}

func (u *UserUseCase) DeleteUser(ctx context.Context, ids []string) error {
	tx := u.ur.GetDB().Begin()
	if tx != nil {
		err := u.ur.DeleteUserByIds(ctx, ids, tx)
		if err != nil {
			tx.Rollback()
			return err
		}
		tx.Commit()
		return nil
	}
	return mstr.DeleteError
}

func (u *UserUseCase) GetUserInfo(ctx context.Context, id string) (*pb.LoginUserReply, error) {
	user, err := u.ur.GetUserById(ctx, id)
	if err != nil {
		return nil, err
	}
	token, err := u.au.GetToken(ctx)
	if err != nil {
		return nil, err
	}
	user.Token = &token
	var reply = new(pb.LoginUserReply)
	// get the user role permission and the operation
	roles, err := u.srr.GetSysRoleByUserId(ctx, user.ID)
	if err != nil || len(roles) < 1 {
		return nil, errors.New("查询用户的角色失败")
	}
	operations, err := u.sor.GetSysOperationByRoleId(ctx, roles[0].ID)
	if err != nil || len(operations) < 1 {
		return nil, errors.New("查询用户的角色下面的功能错误")
	}
	permissions, err := u.spr.GetSysPermissionByRoleId(ctx, roles[0].ID)
	if err != nil || len(permissions) < 1 {
		return nil, errors.New("查询用户的权限错误")
	}
	//
	reply.RoleId = roles[0].ID
	reply.RoleName = *roles[0].RoleName
	for _, role := range roles {
		reply.RoleList = append(reply.RoleList, &pb.RoleInfo{
			Id:       role.ID,
			RoleName: *role.RoleName,
		})
	}
	reply.UserPermissions = getRootPermission(permissions, operations)
	reply.Id = user.ID
	var area = []*pb.Area{}
	areas, _ := u.sua.GetSysAreaByUserId(ctx, user.ID)
	for _, serverArea := range areas {
		area = append(area, &pb.Area{
			AreaId:   *serverArea.ID,
			AreaName: *serverArea.Name,
		})
	}
	reply.Area = area
	if user.CertificatesID != nil {
		reply.CertificatesId = *user.CertificatesID
	}
	if user.Username != nil {
		reply.Username = *user.Username
	}
	if user.JobName != nil {
		reply.JobName = *user.JobName
	}
	if user.Mailbox != nil {
		reply.Mailbox = *user.Mailbox
	}
	if user.Mobile != nil {
		reply.Mobile = *user.Mobile
	}
	if user.RealName != nil {
		reply.RealName = *user.RealName
	}
	if user.UserType != nil {
		reply.UserType = *user.UserType
	}
	if user.Username != nil {
		reply.Username = *user.Username
	}
	if user.Token != nil {
		reply.Token = *user.Token
	}
	return reply, nil
}

func (u *UserUseCase) LoginUser(ctx context.Context, username, password string) (*pb.LoginUserReply, error) {
	user, msg, err := u.ur.TryLogin(ctx, username)
	if err != nil {
		if err.Error() == "record not found" {
			return nil, errors.New(fmt.Sprintf("该用户不存在,%v", msg))
		} else {
			return nil, err
		}
	}
	if ok := tools.Check(password, *user.Password); ok {
		token, err := u.au.NewToken(ctx, user.ID, *user.Username, *user.Mobile)
		if err != nil {
			return nil, err
		}
		user.Token = &token
		var reply = new(pb.LoginUserReply)
		// get the user role permission and the operation
		roles, err := u.srr.GetSysRoleByUserId(ctx, user.ID)
		if err != nil || len(roles) < 1 {
			return nil, errors.New("查询用户的角色失败")
		}
		operations, err := u.sor.GetSysOperationByRoleId(ctx, roles[0].ID)
		if err != nil || len(operations) < 1 {
			return nil, errors.New("查询用户的角色下面的功能错误")
		}
		permissions, err := u.spr.GetSysPermissionByRoleId(ctx, roles[0].ID)
		if err != nil || len(permissions) < 1 {
			return nil, errors.New("查询用户的权限错误")
		}
		//
		reply.RoleId = roles[0].ID
		reply.RoleName = *roles[0].RoleName
		for _, role := range roles {
			reply.RoleList = append(reply.RoleList, &pb.RoleInfo{
				Id:       role.ID,
				RoleName: *role.RoleName,
			})
		}
		reply.UserPermissions = getRootPermission(permissions, operations)
		reply.Id = user.ID
		var area = []*pb.Area{}
		areas, _ := u.sua.GetSysAreaByUserId(ctx, user.ID)
		for _, serverArea := range areas {
			area = append(area, &pb.Area{
				AreaId:   *serverArea.ID,
				AreaName: *serverArea.Name,
			})
		}
		reply.Area = area
		if user.CertificatesID != nil {
			reply.CertificatesId = *user.CertificatesID
		}
		if user.Username != nil {
			reply.Username = *user.Username
		}
		if user.JobName != nil {
			reply.JobName = *user.JobName
		}
		if user.Mailbox != nil {
			reply.Mailbox = *user.Mailbox
		}
		if user.Mobile != nil {
			reply.Mobile = *user.Mobile
		}
		if user.RealName != nil {
			reply.RealName = *user.RealName
		}
		if user.UserType != nil {
			reply.UserType = *user.UserType
		}
		if user.Username != nil {
			reply.Username = *user.Username
		}
		if user.Token != nil {
			reply.Token = *user.Token
		}

		return reply, nil
	} else {
		return nil, errors.New(fmt.Sprintf("用户名或密码错误,%v", msg))
	}
}

func (u *UserUseCase) LogoutUser(ctx context.Context, token string) error {
	//TODO implement me
	panic("implement me")
}

func getRootPermission(permissions []*model.SysPermission, operations []*model.SysOperation) []*pb.UserPermissions {
	var res = []*pb.UserPermissions{}
	//var permissionMap = make(map[string]*model.SysPermission)
	//var operationMap = make(map[string]*model.SysOperation)
	for _, v := range permissions {
		if v.PermissionPid == nil {
			// clear
			permissionVOtreeChildList = []*pb.PermissionTreeVOList{}
			for _, permission := range permissions {
				permissionVOtreeChildSecondList = []*pb.PermissionTreeVOList{}
				getTree(v.ID, v.ID, permission, permissions, operations)
			}
			permissionVOtreeList := permissionVOtreeChildList
			res = append(res, &pb.UserPermissions{
				ActionUrl:            *v.ActionURL,
				Button:               false,
				CreateDateTime:       v.CreateDateTime.Unix(),
				Creator:              fmt.Sprintf("%v", v.Creator),
				Id:                   v.ID,
				IdPath:               *v.IDPath,
				IsSoftDelete:         false,
				Label:                *v.Label,
				PermissionTreeVOList: permissionVOtreeList,
				Router:               *v.Router,
				Sort:                 *v.Sort,
				Type:                 *v.Type,
			})

		}
	}
	return res
}

var permissionVOtreeChildList = []*pb.PermissionTreeVOList{}
var permissionVOtreeChildSecondList = []*pb.PermissionTreeVOList{}
var button = false

func getTree(rootId, curId string, permission *model.SysPermission, permissions []*model.SysPermission, operations []*model.SysOperation) {
	if permission.PermissionPid != nil && *permission.PermissionPid == curId {
		var operationList = []*pb.PermissionTreeVOList_OperationsList{}
		for _, operation := range operations {
			if *operation.PageID == permission.ID {
				operationList = append(operationList, &pb.PermissionTreeVOList_OperationsList{
					CreateDateTime: operation.CreateDateTime.Unix(),
					Creator:        *operation.Creator,
					Id:             operation.ID,
					Name:           *operation.Name,
					PageId:         *operation.PageID,
					Router:         *operation.Router,
				})
			}
		}
		if len(operationList) >= 1 {
			button = true
			if permission.PermissionPid != nil && *permission.PermissionPid == rootId {
				permissionVOtreeChildList = append(permissionVOtreeChildList, &pb.PermissionTreeVOList{
					ActionUrl:            *permission.ActionURL,
					Button:               button,
					CreateDateTime:       permission.CreateDateTime.Unix(),
					Creator:              *permission.Creator,
					Id:                   permission.ID,
					IdPath:               *permission.IDPath,
					Label:                *permission.Label,
					OperationsList:       operationList,
					PermissionPid:        *permission.PermissionPid,
					PermissionTreeVOList: nil,
					Router:               *permission.Router,
					Sort:                 *permission.Sort,
					Type:                 *permission.Type,
				})
			} else {
				permissionVOtreeChildSecondList = append(permissionVOtreeChildSecondList, &pb.PermissionTreeVOList{
					ActionUrl:            *permission.ActionURL,
					Button:               button,
					CreateDateTime:       permission.CreateDateTime.Unix(),
					Creator:              *permission.Creator,
					Id:                   permission.ID,
					IdPath:               *permission.IDPath,
					Label:                *permission.Label,
					OperationsList:       operationList,
					PermissionPid:        *permission.PermissionPid,
					PermissionTreeVOList: nil,
					Router:               *permission.Router,
					Sort:                 *permission.Sort,
					Type:                 *permission.Type,
				})
			}
		} else {
			for _, sysPermission := range permissions {
				getTree(rootId, permission.ID, sysPermission, permissions, operations)
			}
			button = false
			permissionVOtreeChildList = append(permissionVOtreeChildList, &pb.PermissionTreeVOList{
				ActionUrl:            *permission.ActionURL,
				Button:               button,
				CreateDateTime:       permission.CreateDateTime.Unix(),
				Creator:              *permission.Creator,
				Id:                   permission.ID,
				IdPath:               *permission.IDPath,
				Label:                *permission.Label,
				OperationsList:       nil,
				PermissionPid:        *permission.PermissionPid,
				PermissionTreeVOList: permissionVOtreeChildSecondList,
				Router:               *permission.Router,
				Sort:                 *permission.Sort,
				Type:                 *permission.Type,
			})
		}
	}
}
